﻿////////////////////////////////////////////////////////////////////////////////////////
//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING THIS SOFTWARE
//
//  By downloading, copying, installing or using the software you agree to this license.
//  If you do not agree to this license, do not download, install, copy or use the software.
//
// Copyright (C) 2013, AerVision Technologies Pty Ltd, all rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
//   * Redistribution's of source code must retain the above copyright notice,
//     this list of conditions and the following disclaimer.
//
//   * Redistribution's in binary form must reproduce the above copyright notice,
//     this list of conditions and the following disclaimer in the documentation
//     and/or other materials provided with the distribution.
//
//   * The name of AerVision Technologies, may not be used to endorse or promote products
//     derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors to demonstrate 
// www.AerCloud.net Framework as a Service API (FaaS), "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the copyright holder or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
////////////////////////////////////////////////////////////////////////////////////////

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Threading;

namespace App_AerCloudDemo.Utils
{
    public class ImageLoader : Image
    {
        public string tag { get; private set; }
        public string imageName { get; private set; }
        public string personName { get; private set; }

        public ImageLoader(string personName, string imageName, string imageTag = "")
        {
            this.personName = personName;
            this.imageName = imageName;
            this.tag = imageTag;

            Source = ImageCache.loadingImage;

            Task.Factory.StartNew(() =>
            {
                var temp = AerCloudNet_Interface.GetImage(personName, imageName);
                Dispatcher.Invoke(new Action(() =>
                {
                    if (temp != null)
                        Source = ImageUtils.Resize(temp.asBitmap, new Size(128, 128));
                }
                ));
            }
            );
        }
    }

    public class ImageUtils
    {
        public static void ForceUIToUpdate()
        {
            var frame = new DispatcherFrame();
            Dispatcher.CurrentDispatcher.Invoke(DispatcherPriority.Render, new DispatcherOperationCallback(delegate(object parameter)
            {
                frame.Continue = false;
                return null;
            }), null);
            Dispatcher.PushFrame(frame);
        }

        static public BitmapSource TileImages(List<BitmapSource> Images, Size tileSize)
        {
            if (Images == null)
                return null;

            if (Images.Count == 0)
                return null;

            var renderBitmap = new RenderTargetBitmap((int)(Images.Count() * tileSize.Width), (int)tileSize.Height, 96.0, 96.0, PixelFormats.Pbgra32);

            var dv = new DrawingVisual();
            using (var dc = dv.RenderOpen())
            {
                for (int i = 0; i < Images.Count(); i++)
                    dc.DrawImage(Images[i], new Rect((int)(tileSize.Width * i), 0.0, (int)tileSize.Width, (int)tileSize.Height));
            }
            renderBitmap.Render(dv);
            renderBitmap.Freeze();
            return renderBitmap;
        }


        static public BitmapSource Resize(BitmapSource bitmap, Size size)
        {
            if (bitmap == null)
                return null;

            var renderBitmap = new RenderTargetBitmap((int)size.Width, (int)size.Height, 96.0, 96.0, PixelFormats.Pbgra32);

            var dv = new DrawingVisual();
            using (var dc = dv.RenderOpen())
            {
                dc.DrawImage(bitmap, new Rect(0.0, 0.0, (int)size.Width, (int)size.Height));
            }
            renderBitmap.Render(dv);
            renderBitmap.Freeze();
            return renderBitmap;
        }

        public static BitmapSource CropFace(BitmapSource bitmap, Rect faceRec)
        {
            var rect = new Rect((int)(faceRec.X - faceRec.Width / 4),
                                     (int)(faceRec.Y - faceRec.Height * 0.4), (int)(faceRec.Width * 1.5),
                                     (int)(faceRec.Height * 1.5));
            if (rect.X < 0)
            {
                rect.Width += rect.X;
                rect.X = 0;
            }
            if (rect.Y < 0)
            {
                rect.Height += rect.Y;
                rect.Y = 0;
            }
            if ((rect.X + rect.Width) > bitmap.PixelWidth)
                rect.Width += bitmap.PixelWidth - (rect.X + rect.Width);
            if ((rect.Y + rect.Height) > bitmap.PixelHeight)
                rect.Height += bitmap.PixelHeight - (rect.Y + rect.Height);

            rect.Width = Math.Min(rect.Width, rect.Height);
            rect.Height = rect.Width;

            int d = Math.Min(256, (int)rect.Width);
            return CropRect(bitmap, rect, PixelFormats.Bgr24, new Size(d, d));
        }

        public static BitmapSource CropRect(BitmapSource image, Rect rect, PixelFormat outputPixelFormat, Size outputSize)
        {
            if (image != null)
            {
                var cropped = new CroppedBitmap(image, new Int32Rect((int)rect.X, (int)rect.Y, (int)rect.Width, (int)rect.Height));
                var encoder = new JpegBitmapEncoder();
                var memoryStream = new MemoryStream();
                var temp = new BitmapImage();
                encoder.Frames.Add(BitmapFrame.Create(cropped));
                encoder.Save(memoryStream);
                temp.BeginInit();
                temp.StreamSource = new System.IO.MemoryStream(memoryStream.ToArray());
                temp.EndInit();
                memoryStream.Close();

                var visual = new DrawingVisual();
                var dc = visual.RenderOpen();
                var brush = new ImageBrush(temp);
                var r = new Rect(0, 0, outputSize.Width, outputSize.Height);
                dc.DrawRectangle(brush, null, r);
                dc.Close();

                var bitmap = new RenderTargetBitmap((int)r.Width, (int)r.Height, 96, 96, PixelFormats.Pbgra32);
                bitmap.Render(visual);

                if (outputPixelFormat != bitmap.Format)
                {
                    var fcbit = new FormatConvertedBitmap(bitmap, outputPixelFormat, null, 0.0);
                    return fcbit;
                }
                else
                {
                    return bitmap;
                }
            }
            else return null;
        }

        static public byte[] EncodeBitmapPng(BitmapSource bitmap)
        {
            if (bitmap == null)
                return null;

            var encoder = new PngBitmapEncoder();

            encoder.Frames.Add(BitmapFrame.Create(new FormatConvertedBitmap(bitmap, PixelFormats.Bgr24, null, 0.0)));
            using (MemoryStream ms = new MemoryStream())
            {
                encoder.Save(ms);
                return ms.ToArray();
            }
        }

        static public byte[] EncodeBitmapJpeg(BitmapSource bitmap)
        {
            if (bitmap == null)
                return null;

            var encoder = new JpegBitmapEncoder();

            encoder.Frames.Add(BitmapFrame.Create(new FormatConvertedBitmap(bitmap, PixelFormats.Bgr24, null, 0.0)));
            using (MemoryStream ms = new MemoryStream())
            {
                encoder.Save(ms);
                return ms.ToArray();
            }
        }

        static public BitmapSource DecodePng(byte[] data)
        {
            if (data == null)
                return null;

            using (var stream = new MemoryStream(data))
            {
                var decoder = new PngBitmapDecoder(stream, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.OnLoad);
                return decoder.Frames[0];
            }
        }

        static public BitmapSource DecodeJpg(byte[] data)
        {
            if (data == null)
                return null;

            using (var stream = new MemoryStream(data))
            {
                var decoder = new JpegBitmapDecoder(stream, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.OnLoad);
                return decoder.Frames[0];
            }
        }
    }
}
